#!/usr/bin/env bash
# 开发时间：2024年9月
# 作者：刘斌
# 脚本说明：此脚本用于识别给定的IP地址列表中的无法访问的主机，并将这些主机的信息记录到文件中。
# 脚本版本：1.0

set -euo pipefail
IFS=$'\n\t'

ERROR_LOG="error.log"
DOWN_HOSTS_FILE="down_hosts.txt"
NMAP_TEMP_FILE=$(mktemp)
LOG_FILE="scan_log.txt"

true > $LOG_FILE
# 日志记录函数
log_message() {
    local message="$(date '+%Y-%m-%d %H:%M:%S') -$1"
    echo "$message"               # 打印到标准输出
    echo "$message" >>"$LOG_FILE" # 追加到日志文件
}

# 初始化日志文件
log_message "Starting script execution."

# 清理临时文件和处理信号
clean_up() {
    rm -f "$NMAP_TEMP_FILE"
}
trap clean_up EXIT
trap 'echo "Error: Script interrupted by user." >&2; exit 1' INT
trap 'echo "Error: Script terminated by signal." >&2; exit 1' TERM

# 检查是否提供了文件名参数
if [ $# -eq 0 ]; then
    log_message "Usage: $0 <filename>"
    exit 1
fi

# 检查文件是否存在
FILE=$1
if [ ! -f "$FILE" ]; then
    log_message "Error: File '$FILE' not found."
    exit 1
fi

# 校验IP地址格式
validate_ip() {
    local ip=$1
    local re='^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
    [[ $ip =~ $re ]] && [[ ! $ip =~ ^(0\.|255\.|127\.) ]] && [[ ${ip##*.} != 0 ]]
}

# 函数：验证IP地址列表
validate_ip_addresses() {
    local file=$1
    local line_number=0
    local valid_ips=0
    local total_lines=0
    local empty_lines=0

    log_message "Starting IP address validation..."
    while IFS= read -r line || [[ -n "$line" ]]; do
        line_number=$((line_number + 1))
        total_lines=$((total_lines + 1))

        if [[ -z "$line" ]]; then
            empty_lines=$((empty_lines + 1))
        elif ! validate_ip "$line"; then
            echo "Invalid IP address: $line (Line$line_number)" | tee -a "$ERROR_LOG" >&2
        else
            valid_ips=$((valid_ips + 1))
        fi
    done <"$file"

    # 打印摘要
    log_message "IP address validation completed."
    log_message "**************************************************************"
    log_message "* Total lines processed: $total_lines"
    log_message "* Valid IP addresses found: $valid_ips"
    log_message "* Empty lines detected: $empty_lines"
    log_message "* Invalid entries: $((total_lines - valid_ips - empty_lines))"
    log_message "**************************************************************"

}

# 验证IP地址
validate_ip_addresses "$FILE"

# 检查错误日志文件
if [ -s "$ERROR_LOG" ]; then
    log_message "Errors were found in the IP list. Please check the error log: $ERROR_LOG" >&2
    exit 1
fi

# 检查nmap是否安装
if ! command -v nmap &>/dev/null; then
    log_message "Error: nmap is not installed or not in PATH."
    exit 1
fi

# 函数：处理nmap扫描结果
process_nmap_output() {
    local input_file="$1"
    local output_file="$2"

    # 使用 awk 解析 nmap 输出，提取状态为 "Down" 的 IP 地址
    awk '/Status: Down/ {print $2}' "$input_file" >"$output_file"

    return 0
}

# 函数：执行 nmap 扫描
perform_nmap_scan() {
    local input_file="$1"
    local total_ips=$(wc -l < "$input_file")
    local processed_ips=0

    log_message "Starting nmap scan on $total_ips IP addresses..."

    # 执行 nmap ping 扫描，实时输出结果
    nmap -iL "$input_file" -v -sn -PE -PP -n -oG - | while IFS= read -r line; do
        if [[ "$line" == "Host:"* ]]; then
            processed_ips=$((processed_ips+1))
            local percentage=$((processed_ips * 100 / total_ips))
            echo -ne "Scanning progress: $percentage% ($processed_ips/$total_ips)\r"
            # log_message "Scanning progress: $percentage% ($processed_ips/$total_ips)"
        fi
        echo "$line" >> "$NMAP_TEMP_FILE"
    done

    echo "" # 新行，为了格式化输出
    log_message "Nmap scan completed."
    # 处理 nmap 扫描结果，提取无法访问的主机
    if ! process_nmap_output "$NMAP_TEMP_FILE" "$DOWN_HOSTS_FILE"; then
        log_message "Error: Failed to process nmap output." >&2
        return 1
    fi

    clean_up
    # 检查 down_hosts.txt 文件是否存在且可读
    if [ ! -f "$DOWN_HOSTS_FILE" ] || [ ! -r "$DOWN_HOSTS_FILE" ]; then
        log_message "Error: The file $DOWN_HOSTS_FILE does not exist or is not readable."
        return 1
    fi

    # 如果 down_hosts.txt 为空，说明所有主机都在线
    if [ ! -s "$DOWN_HOSTS_FILE" ]; then
        log_message "All hosts are up. No down hosts to report."
        return 0
    fi

    # 输出无法访问的主机总数，并打印主机列表
    log_message "**************************************************************"
    log_message "* Total down hosts: $(wc -l <"$DOWN_HOSTS_FILE")"
    log_message "* Please check the down hosts list: $DOWN_HOSTS_FILE"
    log_message "**************************************************************"

}

# 主脚本逻辑：验证IP地址后执行nmap扫描
if ! perform_nmap_scan "$FILE"; then
    log_message "Error occurred during nmap scan or processing." >&2
    exit 1
fi

log_message "Done."
exit 0
